package com.itheima.easy.config;

import com.itheima.easy.properties.SecurityConfigProperties;
import com.itheima.easy.security.JwtAuthorizationManager;
import com.itheima.easy.security.RestAuthoricationEntryPoint;
import com.itheima.easy.security.RestfulAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * @ClassName SecurityConfig.java
 * @Description 权限核心配置类
 */
@EnableWebSecurity
@EnableConfigurationProperties(SecurityConfigProperties.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    SecurityConfigProperties securityConfigProperties;

    @Autowired
    UserDetailsService userDetailsService;

    @Autowired
    JwtAuthorizationManager jwtAuthorizationManager;

    @Autowired
    RestfulAccessDeniedHandler restfulAccessDeniedHandler;

    @Autowired
    RestAuthoricationEntryPoint restAuthoricationEntryPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable()
            // 禁用session机制
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeHttpRequests()
            // 指定某些接口不需要通过验证即可访问。像登陆、注册接口肯定是不需要认证的
            .antMatchers(securityConfigProperties.getIgnoreUrl()
                .toArray(new String[securityConfigProperties.getIgnoreUrl().size()]))
            .permitAll()
            // 指定授权处理器
            .anyRequest().access(jwtAuthorizationManager)
            .and()
            // 禁用缓存
            .headers().cacheControl();
        // 添加自定义未授权和未登陆结果返回
        http.exceptionHandling()
            .accessDeniedHandler(restfulAccessDeniedHandler)//已登录成功，但是请求的url超出其权限，默认会响应403状态码
            .authenticationEntryPoint(restAuthoricationEntryPoint);//用户在未登录状态下直接请求需要登录的接口，应该报401
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 指定UserDetailService和加密器
        auth.userDetailsService(userDetailsService).passwordEncoder(bcryptPasswordEncoder());
    }

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    /**
     * BCrypt密码编码
     * @return
     */
    @Bean
    public BCryptPasswordEncoder bcryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

}
